//
//  config.swift
//  jocool
//
//  Created by tong on 16/6/11.
//  Copyright © 2016年 zhuxietong. All rights reserved.
//

import Foundation
import UIKit
import Eelay


fileprivate var tasks_map:[String:Any] = [:]

extension Array{
 
    public class AsyncTask<T>:NSObject{
        public typealias Target = T
        public var index:Int = 0
        public let element:Element
        public init(elemnt:Element) {
            self.element = elemnt
        }
        public enum Status {
            case waiting
            case finish
        }
        public var status = Status.waiting
        
        public var result:Target? = nil
        public var message:String? = nil
        
        public func success(_ target:Target) {
            finishBlock(self,target,"success")
        }
        public func error(_ error:String) {
            finishBlock(self,nil,error)
        }
        
        public var finishBlock:(_:AsyncTask<T>,_:Target?,_:String)->Void = {_,_,_ in}
        deinit {
        }
        
    }
        
    
    public func async<T>(
        block:@escaping(_:Element,_:Int,_:AsyncTask<T>)->Void,
        finish:@escaping(_:[T])->Void,
        error:@escaping((_:String)->Void) = {print("error: \($0)")})
    {
        let tasks = self.map{AsyncTask<T>(elemnt: $0)}
        let tasks_id = UUID().uuidString
        tasks_map[tasks_id] = tasks
        
        let tast_num = tasks.count
        var is_finish = false
        
        for (i,task) in tasks.enumerated() {
            task.index = i
        }

        var finish_tasks:[(Int,T)] = []
        for (i,task) in tasks.enumerated() {
            let finishBlock = { (task:AsyncTask<T>,result:T?, msg:String) in
                task.message = msg
                task.result = result
                task.status = .finish
                guard let result_ = result else {
                    if !is_finish{
                        is_finish = true
                        DispatchQueue.main.async(execute: {
                            error(msg)
                        })
                        tasks_map.removeValue(forKey: tasks_id)
                    }
                    return
                }
                finish_tasks.append((task.index,result_))
                if tast_num <= finish_tasks.count{
                    if !(is_finish){
                        let finish_tasks_ = finish_tasks.sorted { t1, t2 in
                            return t1.0 < t2.0
                        }.map { one in
                            return one.1
                        }
                        DispatchQueue.main.async(execute: {
                            is_finish = true
                            finish(finish_tasks_)
                        })
                    }
                    tasks_map.removeValue(forKey: tasks_id)
                    is_finish = true
                }
            }
            task.finishBlock = finishBlock
            block(task.element,i,task)
        }
    }

    
}
